//
// Copyright (c) 2011 Alex Nesterenko
//

#ifndef NANE_OGLRENDERSYSTEM_H
#   define NANE_OGLRENDERSYSTEM_H

#   include "nane/RenderSystem/IRenderSystem.h"
#   include "nane/RenderSystem/ogl/OGLAPI.h"

namespace nane
{
    class OGLWindowContext;
    class OGLBufferManager;

    class OGLRenderSystem
        : public IRenderSystem
    {
    public:
        OGLRenderSystem();
        ~OGLRenderSystem();

    public:
        bool initialize();
        void shutdown();

        bool initializeContext( IWindow::OSHandle _windowHandle, uint32 _resWidth, uint32 _resHeight );
        IVertexBuffer* createVertexBuffer( EResourceUsage::raw_type _usage, uint32 _verticesNum, uint32 _vertexSize
                                         , VertexElement* _elements, uint32 _elementsNum, byte* _initData );
        void releaseVertexBuffer( IVertexBuffer* _vertexBuffer );
        byte* lockVertexBuffer( IVertexBuffer* _vertexBuffer, uint32 _offset, uint32 _size );
        void unlockVertexBuffer( IVertexBuffer* _vertexBuffer );
        void setVertexBuffer( uint16 _streamNumber, IVertexBuffer* _vertexBuffer );
        IIndexBuffer* createIndexBuffer( EResourceUsage::raw_type _usage, uint32 _indiciesNum, uint16* _initData );
        void releaseIndexBuffer( IIndexBuffer* _indexBuffer );
        uint16* lockIndexBuffer( IIndexBuffer* _indexBuffer, uint32 _offset, uint32 _size );
        void unlockIndexBuffer( IIndexBuffer* _indexBuffer );
        void setIndexBuffer( IIndexBuffer* _indexBuffer );
        ITexture* createTexture( EResourceUsage::raw_type _usage, uint32 _width, uint32 _height, EPixelFormat::raw_type _format );
        void releaseTexture( ITexture* _texture );
        byte* lockTexture( ITexture* _texture, uint32 _x, uint32 _y, uint32 _width, uint32 _height, uint32* _pitch );
        void unlockTexture( ITexture* _texture );
        void setTexture( uint32 _stage, ITexture* _texture );
        bool setRenderTarget( IRenderTarget* _target );
        bool beginScene();
        void endScene();
        void drawPrimitive( EPrimitiveType::raw_type _type, uint32 _baseVertexIndex, uint32 _verticesNum );
        void drawIndexedPrimitive( EPrimitiveType::raw_type _type, uint32 _baseVertexIndex, uint32 _minIndex
                                         , uint32 _verticesNum, uint32 _startIndex, uint32 _primitiveCount );
        void clearRenderTarget( EFrameBufferType::raw_type _type, uint32 _color, float _depth, uint16 _stencil );
        void swapBuffers();
        void setProjectionMatrix( const float* _projection );
        void setModelViewMatrix( const float* _modelview );
        void setLightingEnable( bool _enable );
        void setCullMode( ECullMode::raw_type _mode );

        IVertexShader* createVertexShader( const byte* _buffer, uint32 _size );
        bool setVertexShader( IVertexShader* _vertexShader );
        void releaseVertexShader( IVertexShader* _vertexShader );
        
        IPixelShader* createPixelShader( const byte* _buffer, uint32 _size );
        bool setPixelShader( IPixelShader* _pixelShader );
        void releasePixelShader( IPixelShader* _pixelShader );
        
    private:
        void setActiveTexture_( GLuint _textureID );

    private:
        OGLWindowContext* m_windowContext;
        OGLBufferManager* m_bufferManager;
        GLuint m_activeTexture;
        ITexture* m_currentTexture;
        bool m_depthMask;
    };
}   // namespace nane

#endif	// NANE_OGLRENDERSYSTEM_H
